package com.ds.esd.localproxy.handler;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.TypeUtils;
import com.ds.common.JDSException;
import com.ds.common.util.ClassUtility;
import com.ds.common.util.IOUtility;
import com.ds.config.ListResultModel;
import com.ds.config.ResultModel;
import com.ds.config.TreeListResultModel;
import com.ds.context.JDSActionContext;
import com.ds.enums.service.RequestType;
import com.ds.esd.client.ESDClient;
import com.ds.esd.client.ESDFacrory;
import com.ds.esd.client.ProjectVersion;
import com.ds.esd.custom.CustomViewFactory;
import com.ds.esd.custom.DataComponent;
import com.ds.esd.custom.bean.CustomDynDataBean;
import com.ds.esd.custom.bean.CustomModuleBean;
import com.ds.esd.custom.bean.MethodConfig;
import com.ds.esd.custom.module.annotation.DynLoadAnnotation;
import com.ds.esd.editor.enums.PackagePathType;
import com.ds.esd.editor.enums.PackageType;
import com.ds.esd.tool.module.EUModule;
import com.ds.esd.tool.ui.component.Component;
import com.ds.esd.tool.ui.component.data.APICallerComponent;
import com.ds.esd.tool.ui.component.panel.grid.PageBarComponent;
import com.ds.esd.tool.ui.enums.ComponentType;
import com.ds.esd.tool.ui.enums.event.enums.ModuleEventEnum;
import com.ds.esd.tool.ui.module.ModuleComponent;
import com.ds.esd.tool.ui.module.ModuleProperties;
import com.ds.server.httpproxy.core.*;
import com.ds.web.BaseParamsEnums;
import com.ds.web.RequestMethodBean;
import com.ds.web.RequestParamBean;
import com.ds.web.util.AnnotationUtil;
import com.ds.web.util.JSONGenUtil;
import ognl.OgnlException;
import ognl.OgnlRuntime;
import org.springframework.web.bind.annotation.RequestBody;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public abstract class AbstractRADHandler extends AbstractHandler {


    public boolean sendModule(String className, HttpRequest request, HttpResponse response) {
        try {
            ESDClient client = ESDFacrory.getESDClient();
            EUModule module = null;
            String projectName = this.getProjectName(request);
            RequestMethodBean requestMethodBean = getRequestMethodBean(request);
            PackagePathType packagePathType = null;
            Map allParamsMap = this.getAllParamMap(requestMethodBean, request);
            if (requestMethodBean.getUrl().indexOf("/") > -1) {
                String packageUrl = requestMethodBean.getUrl().substring(0, requestMethodBean.getUrl().lastIndexOf("/"));
                packagePathType = PackagePathType.startPath(packageUrl);
            }

            if (packagePathType == null || packagePathType.getApiType().equals(PackageType.local)) {
                module = client.getModule(className, projectName, true);
            } else {
                module = client.getDSMModule(className, allParamsMap);
            }

            if (module == null) {
                MethodConfig methodConfig = CustomViewFactory.getInstance().getMethodAPIBean(className, projectName);
                module = CustomViewFactory.getInstance().buildView(methodConfig, projectName, allParamsMap, false);
                ModuleComponent<ModuleProperties, Component, ModuleEventEnum> moduleComponent = module.getComponent();

                if (moduleComponent.getProperties().getDynLoad()!=null &&moduleComponent.getProperties().getDynLoad()) {
                    client.saveModule(module);
                }

            }


            if (JSONGenUtil.getInnerReturnType(requestMethodBean).isAssignableFrom(EUModule.class)) {
                Object service = this.getService(requestMethodBean, request);
                ResultModel<EUModule> resultModel = (ResultModel<EUModule>) OgnlRuntime.callMethod(getOgnlContext(), service, requestMethodBean.getMethodName(), new Object[]{module});
                module = resultModel.get();
            }


            if (module != null) {

                module.getComponent().fillParams(requestMethodBean.getParamSet(), allParamsMap);
                module.getComponent().fillFormValues(allParamsMap, false);
                String mimeType = "application/javascript";
                String json = client.genJSON(module, null).toString();
                response.sendResponse(json, mimeType + ";");
            } else {
                return false;
            }
        } catch (Exception e) {
            response.sendError(500, e.getMessage());
            e.printStackTrace();
        }
        return true;
    }

    private EUModule getEUModule(RequestMethodBean methodBean, HttpRequest request, Map<String, Object> allParamsMap) {
        EUModule module = null;
        try {
            MethodConfig methodAPIBean = ESDFacrory.getESDClient().getMethodAPIBean(methodBean.getUrl(), getProjectName(request));
            CustomDynDataBean customDynDataBean = methodAPIBean.getDynDataBean();
            CustomModuleBean moduleAnnotation = methodAPIBean.getModuleBean();
            Object obj = allParamsMap.get(CUSSCLASSNAME);

            if (customDynDataBean != null && moduleAnnotation != null) {
                if (!customDynDataBean.getRefClassName().equals("")) {
                    String projectName = customDynDataBean.getProjectName();
                    if (projectName.equals("")) {
                        projectName = this.getProjectName(request);
                    }
                    ProjectVersion projectVersion = ESDFacrory.getESDClient().getProjectVersionByName(projectName);
                    module = projectVersion.getModule(customDynDataBean.getRefClassName());
                    if (module == null) {
                        module = ESDFacrory.getESDClient().rebuildCustomModule(customDynDataBean.getRefClassName(), projectName, allParamsMap);
                    }
                    if (module != null) {
                        module.getComponent().getRealModuleComponent().fillFormValues(allParamsMap, true);
                    }
                } else {
                    String projectName = this.getProjectName(request);
                    Class componentClass = JSONGenUtil.getInnerReturnType(methodAPIBean.getMethod());
                    if (ModuleComponent.class.isAssignableFrom(componentClass)) {
                        module = ESDFacrory.getESDClient().buildDynCustomModule(componentClass, allParamsMap, true);
                    } else {
                        module = CustomViewFactory.getInstance().createRealView(methodAPIBean, null, projectName, allParamsMap, true);
                    }
                }
            } else {
                String projectName = this.getProjectName(request);
                String currClassName = obj.toString();
                module = ESDFacrory.getESDClient().getModule(currClassName, projectName);
                if (module == null) {
                    module = ESDFacrory.getESDClient().getDSMModule(currClassName, allParamsMap);
                }
                if (module != null) {
                    module.getComponent().getRealModuleComponent().fillFormValues(allParamsMap, true);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return module;
    }

    @Override
    public Object invokMethod(RequestMethodBean methodBean, HttpRequest request, HttpResponse response) throws ClassNotFoundException, OgnlException {
        Object object = null;
        Object service = this.getService(methodBean, request);
        Map<String, Object> allParamsMap = this.getAllParamMap(methodBean, request);
        Map<String, String> paramsMap = methodBean.getParamsMap();
        Set<RequestParamBean> keySet = methodBean.getParamSet();
        List<Object> objects = new ArrayList<>();
        List<Class> objectTyps = new ArrayList<>();
        DynLoadAnnotation dynAnnotation = AnnotationUtil.getMethodAnnotation(methodBean.getSourceMethod(), DynLoadAnnotation.class);
        ModuleComponent moduleComponent = null;
        for (RequestParamBean paramBean : keySet) {
            Class ctClass = ClassUtility.loadClass(paramsMap.get(paramBean.getParamName()));
            String iClassName = ctClass.getName();
            Class iClass = ClassUtility.loadClass(iClassName);
            String key = paramBean.getParamName();
            Object value = null;
            try {
                RequestBody requestBody = null;
                for (Annotation annotation : paramBean.getAnnotations()) {
                    if (annotation.annotationType().equals(RequestBody.class)) {
                        requestBody = (RequestBody) annotation;
                    }
                }
                if (requestBody != null) {
                    if (methodBean.getRequestType().equals(RequestType.JSON)) {
                        String jsonData = IOUtility.toString(request.getPostData());
                        JSONObject requestBodyValue = JSONObject.parseObject(jsonData);
                        for (BaseParamsEnums baseParams : BaseParamsEnums.values()) {
                            if (requestBodyValue.containsKey(baseParams.name())) {
                                JDSActionContext.getActionContext().getContext().put(baseParams.name(), requestBodyValue.get(baseParams.name()));
                            }
                        }
                        value = JSONObject.parseObject(jsonData, paramBean.getParamClass());
                    }
                } else if (Request.class.isAssignableFrom(iClass)) {
                    value = request;
                } else if (ModuleComponent.class.isAssignableFrom(iClass)) {

                    if (moduleComponent == null) {

                        moduleComponent = getEUModule(methodBean, request, allParamsMap).getComponent().getRealModuleComponent();
                    }
                    value = moduleComponent;
                } else if (EUModule.class.isAssignableFrom(iClass)) {
                    value = getEUModule(methodBean, request, allParamsMap);

                } else if (Response.class.isAssignableFrom(iClass)) {
                    value = response;
                } else {
                    switch (methodBean.getRequestType()) {
                        case FORM:
                            if (iClass.isArray()) {
                                if (JSONObject.parseArray(allParamsMap.get(key).toString()).size() > 0) {
                                    value = JSONObject.parseArray(allParamsMap.get(key).toString(), iClass.getComponentType()).toArray();
                                } else {
                                    value = Array.newInstance(iClass.getComponentType(), 0);
                                }
                            } else {
                                if (paramBean.getJsonData()) {
                                    value = JSONObject.parseObject(allParamsMap.get(key).toString(), iClass);
                                } else {
                                    value = TypeUtils.cast(allParamsMap.get(key), iClass, null);
                                }
                            }
                            break;

                        default:
                            value = TypeUtils.cast(allParamsMap.get(paramBean.getParamName()), iClass, null);
                            break;
                    }

                }
            } catch (Throwable e) {
                e.printStackTrace();
                logger.error("参数转换错误：  [" + paramBean.getParamName() + "] convertValue err " + e.getMessage());
            }
            objectTyps.add(iClass);
            objects.add(value);
        }

        if (service != null) {
            if (dynAnnotation != null) {
                object = OgnlRuntime.callMethod(getOgnlContext(), service, methodBean.getMethodName(), objects.toArray());
                if (JSONGenUtil.getInnerReturnType(methodBean).isAssignableFrom(EUModule.class)) {
                    EUModule otherModule = ((ResultModel<EUModule>) object).getData();
                    try {
                        ((ResultModel) object).setData(otherModule.getRealComponents(true));
                    } catch (JDSException e) {
                        e.printStackTrace();
                    }
                } else if (!JSONGenUtil.getInnerReturnType(methodBean).isAssignableFrom(Component.class) || !dynAnnotation.refClassName().equals("")) {

                    if (moduleComponent == null) {
                        try {
                            moduleComponent = getEUModule(methodBean, request, allParamsMap).getComponent().getRealModuleComponent().clone();
                        } catch (JDSException e) {
                            e.printStackTrace();
                        }
                    }

                    if (moduleComponent != null) {
                        ResultModel resultModel = (ResultModel) object;
                        boolean syncLoad = false;
                        if (moduleComponent instanceof DataComponent) {
                            List<APICallerComponent> componentList = moduleComponent.findComponents(ComponentType.APICaller, "Reload");
                            for (APICallerComponent api : componentList) {
                                if (api.getAlias().equals("Reload") && api.getProperties().getAutoRun()) {
                                    syncLoad = true;
                                    // api.getProperties().setAutoRun(false);
                                }
                            }
                            if (syncLoad) {
                                ((DataComponent) moduleComponent).setData(resultModel.getData());
                                if (resultModel instanceof TreeListResultModel) {
//
                                } else if (resultModel instanceof ListResultModel) {
                                    ListResultModel listResultModel = (ListResultModel) object;
                                    List<PageBarComponent> pageBarComponents = moduleComponent.findComponents(ComponentType.PageBar, null);
                                    if (pageBarComponents.size() > 0) {
                                        pageBarComponents.get(0).setData(Integer.valueOf(listResultModel.getSize()));
                                    }
                                }
                            }
                        }
                    }
                    ((ResultModel) object).setData(moduleComponent.getTopComponents(true));

                }
            } else {
                object = OgnlRuntime.callMethod(getOgnlContext(), service, methodBean.getMethodName(), objects.toArray());
            }
        } else {
            object = OgnlRuntime.callMethod(getOgnlContext(), service, methodBean.getMethodName(), objects.toArray());
        }

        return object;
    }


}
